<?php
/**
 * @link https://ym2.cleverstone.top
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

use yii\helpers\Json;
use builder\helper\Url;
use builder\helper\RegEx;
use builder\helper\App;

/* ====== 表单构建器 ====== */

/* @var \yii\web\View $this */
/** @var \builder\form\FormBuilder $context 当前表单组件实例 */
/** @var array $body 表单内容 */
/** @var array $bodyJsOptions 表单内容JS选项 */
/** @var bool $autoClose 是否提交后自动关闭表单 */
/** @var bool $autoBack 是否提交后自动返回 */
/** @var array $submitConfirm 设置表单提交确认框 */
/** @var array $submittedCalls 表单自动提交后的回调, 空数组代表不回调 */
/** @var array $extraJs 额外的JS脚本 */
/** @var array $formDynamicSelect 表单动态select */
/** @var array $formValueLink 表单值连接选项 */
/** @var array $formTrigger 表单触发器选项 */
/** @var array $formWatchScope 表单监听的字段模型 */
/** @var array $submittedRedirect 表单提交后重定向, 空数组代表无操作 */
/** @var array $formDynamicControl 表单动态控件选项 */

// 上下文对象
$context = $this->context;
?>
<script>
    void function (global, top) { "use strict";
        global.ym2App.controller("ym2.ctrl.<?= $context->id ?>", [
            "$scope",
            "$http",
            "ymSpinner",
            "layui",
            "ym2",
            "swal",
            "lodash",
            "ue",
            "Sortable",
            "$timeout",
            "$interval",
            "xmSelect",
            function ($scope, $http, ymSpinner, layui, ym2, swal, lodash, ue, Sortable, $timeout, $interval, xmSelect) {
                // 提交URL
                var formBuilderId = "<?= $context->id ?>";
                var topToastr = top.toastr;
                var topLayer = top.layui.layer;
                var topJquery = top.jQuery;
                var formSubmitUrl = "<?= $context->submitUrl ?>";
                var bodyJsOptions = <?= Json::encode($bodyJsOptions) ?>;
                var submittedCalls = <?= Json::encode($submittedCalls) ?>;
                var submittedRedirectOptions = <?= Json::encode($submittedRedirect) ?>;
                var formDynamicSelect = <?= Json::encode($formDynamicSelect) ?>;

                // 关闭表单弹窗
                $scope.formClose = function () {
                    var layerIndex = topLayer.getFrameIndex(global.name);
                    topLayer.close(layerIndex);

                    return true;
                };

                // 返回上一页
                $scope.formBack = function () {
                    global.history.go(-1);
                    return true;
                };

                // 表单重置
                $scope.formReset = function (event, isInit) {
                    isInit = isInit || false;
                    var ueEditor;
                    var formOptions;
                    var selectLinkDefault;
                    var xselectOptions;

                    <?php foreach ($body as $groupField => $options): ?>

                    // ======================================= 表单组<?= $groupField ?>定义 =======================================

                    formOptions = bodyJsOptions["<?= $groupField ?>"];
                    $scope["<?= $groupField ?>"] = {};
                    <?= RegEx::js($this->renderPhpFile(__DIR__ . '/tpl/app.form.init.php', [
                        'controlItems' => $options['controls'],
                        'groupField' => $groupField,
                    ])) ?>

                    <?php endforeach; ?>

                };

                // 获取表单内容
                $scope.getYm2FormContent = function () {
                    // UE
                    var ueEditor;
                    // 当前分组字段
                    var currentGroupField;
                    // 输出结果
                    var result = {};

                    <?php foreach ($body as $groupField => $options): ?>

                    // ======================================= 表单组<?= $groupField ?>内容提交 =======================================

                    currentGroupField = "<?= $groupField ?>";
                    result[currentGroupField] = {};
                    // 表单控件值获取JS脚本
                    <?= RegEx::js($this->renderPhpFile(__DIR__ . '/tpl/app.form.get.php', [
                        'controlItems' => $options['controls'],
                    ])) ?>
                    <?php endforeach; ?>

                    return result;
                };

                // 表单提交事件
                $scope.formSubmit = function () {
                    var isConfirm = <?= (int)$submitConfirm['show'] ?>;
                    if (!isConfirm) {
                        $scope.runSubmitRequest();
                    } else {
                        ym2.swal.question(
                            top.swal,
                            "<?= $submitConfirm['title'] ?>",
                            "<?= $submitConfirm['content'] ?>",
                            function (result) {
                                //确认提交
                                if (result.isConfirmed) {
                                    $scope.$apply(function () {
                                        $scope.runSubmitRequest();
                                    });
                                }
                            });
                    }
                };
                // 表单值校验
                $scope._actionFormValidation = function() {
                    var formData = $scope.getYm2FormContent();
                    var keyLen = ym2.keys(formData).length;
                    var __isPass = true;

                    // 表单为空检查
                    if (__isPass) {
                        if (keyLen <= 0) {
                            topToastr.warning("请填写表单!");
                            __isPass = false;
                        }
                    }

                    // 普通控件校验
                    if (__isPass) {
                        Loop0:for (var groupField in formData) {
                            var validateOptions = bodyJsOptions[groupField];
                            var currentGroupOptions = formData[groupField];
                            for (var field in currentGroupOptions) {
                                if (
                                    validateOptions
                                    && validateOptions[field]
                                    && validateOptions[field]['required']
                                    && ym2.isEmpty(currentGroupOptions[field])
                                ) {
                                    topToastr.warning('"' + (validateOptions[field]['label'] || field) + '"不可为空!');
                                    __isPass = false;
                                    break Loop0;
                                }
                            }
                        }
                    }

                    // 动态控件校验
                    <?php if (!empty($formDynamicControl)): ?>

                    <?= RegEx::js($this->renderPhpFile(__DIR__ . '/tpl/app.dynamic.control.validate.php', [
                        'formDynamicControl' => $formDynamicControl,
                    ])) ?>
                    <?php endif; ?>

                    // 返回结果
                    if (!__isPass) { return false; }
                    if (keyLen <= 1) {
                        formData = Object.keys(formData).map(function (i) {
                            return formData[i];
                        })[0];
                    }

                    return formData;
                };
                // 发起提交请求
                $scope.runSubmitRequest = function () {
                    // 获取表单数据
                    var formData = $scope._actionFormValidation();
                    if (formData === false) { return; }

                    // 发起请求
                    var flag = ymSpinner.show();
                    $http.post(formSubmitUrl, formData).then(function (result) {
                        ymSpinner.hide(flag);
                        var data = result.data;
                        switch (data.code) {
                            case <?= App::params('http.res.success') ?>: //业务成功
                                // 成功轻提示
                                if (data.msg) {
                                    topToastr.success(data.msg);
                                }

                            <?php if ($autoClose): ?>

                                // 自动关闭弹窗
                                var layerIndex = topLayer.getFrameIndex(global.name);
                                topLayer.close(layerIndex);
                            <?php elseif ($autoBack): ?>

                                // 自动返回上一页
                                global.history.go(-1);
                            <?php endif; ?>

                                // 自动执行回调
                                $scope._actionSubmittedCallback();

                                // 表单提交后重定向,空数组代表无操作
                                $scope._actionSubmittedRedirect(data.data || []);

                                break;
                            case <?= App::params('http.res.failure') ?>: //业务失败
                                topToastr.error(data.msg);
                                break;
                            case <?= App::params('http.res.unauthorized') ?>://授权失效, 去登录
                                // 授权失效, 去登录
                                ym2.swal.timer(
                                    top.swal,
                                    data.msg,
                                    "自动跳转; <a href='<?= Url::to(App::params('admin.route.login'), '') ?>' target='_top'>立即跳转<a/>",
                                    function () {
                                        top.open("<?= Url::to(App::params('admin.route.login'), '') ?>", "_self");
                                    },
                                    3000
                                );

                                break;
                            default://其他
                                topToastr.error(data.msg);
                        }

                    }, function (error) {
                        ymSpinner.hide(flag);
                        topToastr.error(error.data || "系统错误, 发起请求失败!");
                        global.console.error(error);
                    });
                };
                //表单提交后重定向,空数组代表无操作
                $scope._actionSubmittedRedirect = function (data) {
                    var L = Object.keys(submittedRedirectOptions).length;
                    if (L <= 0) {
                        return;
                    }

                    var type = submittedRedirectOptions.type;
                    var url = submittedRedirectOptions.route;
                    var params = submittedRedirectOptions.params || [];

                    if (ym2.keys(params).length) {
                        params = ym2.fillParams(params, data);
                        url = ym2.addUrlQueryParam(url, params);
                    }

                    switch (type) {
                        case "modal"://modal
                            // layer动态唯一索引
                            var activeIndex = topLayer.index;
                            // modal title
                            var title = submittedRedirectOptions.title || '';
                            // modal width
                            var width = submittedRedirectOptions.width || "100%";
                            // modal height
                            var height = submittedRedirectOptions.height || "100%";
                            // modal footer close btn
                            var footerCloseBtn = submittedRedirectOptions.closeBtn;
                            // layer screen obj
                            var layerScreenObj = ym2.layerScreenOptions(width);

                            // iframe 模态框
                            var layerCf = {
                                type: 2, // iframe
                                //skin: 'layui-layer-win10',
                                area: [layerScreenObj.width, height],
                                title: title,
                                shade: 0.3, // 遮罩透明度
                                shadeClose: false, // 点击遮罩区域，关闭弹层
                                //closeBtn: layerScreenObj.closeBtn,
                                maxmin: true, // 允许全屏最小化
                                anim: 0, // 0-6 的动画形式，-1 不开启
                                scrollbar: false, // 打开弹层时，是否允许浏览器出现滚动条。
                                content: url,
                                success: function(layero, index, that){
                                    // 弹层的最外层元素的 jQuery 对象
                                    //console.log(layero);
                                    // 弹层的索引值
                                    //console.log(index);
                                    // 弹层内部原型链中的 this --- 2.8+
                                    //console.log(that);
                                    // 获取iframe的窗口对象, 添加来源追踪
                                    var iframeWin = top[layero.find("iframe")[0]["name"]];
                                    iframeWin.__REFERER_WIN_NAME = global.name;
                                    //键盘事件关闭
                                    topJquery(".ym2_kc_" + activeIndex).focus().on("keydown", function (e) {
                                        // 空格和回车键
                                        if (e.keyCode === 13 || e.keyCode === 32) {
                                            topJquery(this).trigger("click");
                                        }
                                    });
                                },
                            };
                            if (footerCloseBtn) {
                                layerCf.btn = ['<span class="ym2_keydown_close ym2_kc_' + activeIndex + '" tabindex="0">关闭</span>'];
                            }

                            topLayer.open(layerCf);
                            break;
                        case "page"://page
                            var target = submittedRedirectOptions.target;
                            var owin;
                            eval("owin = " + submittedRedirectOptions.window);
                            owin.open(url, target);

                            break;
                    }
                };
                // 提交成功后的刷新回调
                $scope._actionSubmittedCallback = function () {
                    Object.keys(submittedCalls).forEach(function (key) {
                        var callbackMethod = submittedCalls[key];
                        if (key === "self") {//self
                            var selfCbkExport = global.ym2CbkExport || {};
                            if (!callbackMethod.length) {
                                // 回调所有
                                Object.keys(selfCbkExport).forEach(function (key) {
                                    /* $scope 当前表单域 */
                                    selfCbkExport[key].call();
                                });
                            } else {
                                // 指定回调
                                Object.keys(selfCbkExport).forEach(function (key) {
                                    if (lodash.indexOf(callbackMethod, key) !== -1) {
                                        /* $scope 当前表单域 */
                                        selfCbkExport[key].call();
                                    }
                                });
                            }
                        } else {//parent.parent*
                            if (global !== global.parent) {
                                var keysMap = key.split('.');
                                var currentWin = global;
                                var refererWinName = currentWin.__REFERER_WIN_NAME;
                                var parentWin;
                                for (var i = 0; i < keysMap.length; i++) {
                                    parentWin = refererWinName ? top[refererWinName] : currentWin.parent;
                                    refererWinName = parentWin.__REFERER_WIN_NAME;
                                    currentWin = parentWin;
                                }

                                var parentCbkExport = parentWin.ym2CbkExport || {};
                                if (!callbackMethod.length) {
                                    // 回调所有
                                    Object.keys(parentCbkExport).forEach(function (key) {
                                        /* $scope 当前表单域 */
                                        parentCbkExport[key].call();
                                    });
                                } else {
                                    // 指定回调
                                    Object.keys(parentCbkExport).forEach(function (key) {
                                        if (lodash.indexOf(callbackMethod, key) !== -1) {
                                            /* $scope 当前表单域 */
                                            parentCbkExport[key].call();
                                        }
                                    });
                                }
                            }
                        }

                    });
                };

                // 动态控件事件脚本
                <?php if (!empty($formDynamicControl)): ?>

                <?= RegEx::js($this->renderPhpFile(__DIR__ . '/tpl/app.dynamic.control.action.php', [
                    'formDynamicControl' => $formDynamicControl,
                ])) ?>
                <?php endif; ?>

                // 动态下拉控件 - 刷新
                $scope.actionDynamicSelectRefresh = function (controlId, isInit) {
                    isInit = isInit || false;

                    formDynamicSelect.forEach(function (value, index, array) {
                        if (!controlId || controlId === value.__id) {
                            $scope._actionInitDs(value, isInit);
                        }
                    });
                };
                $scope._actionInitDs = function (config, isInit) {
                    // show loading
                    var flag = ymSpinner.show();
                    $http.get(config.dataUrl).then(function (result) {
                        ymSpinner.hide(flag);

                        var data = result.data;
                        switch (data.code) {
                            case <?= App::params('http.res.success') ?>:
                                $scope[config.__id + '__options'] = data.data;

                                if (isInit) {
                                    // 加载完成后, 重新初始化控件默认值
                                    $scope.formReset(null, true);
                                }

                                break;
                            case <?= App::params('http.res.failure') ?>:
                                topToastr.error(data.msg);

                                break;
                            case <?= App::params('http.res.unauthorized') ?>:
                                // 授权失效, 去登录
                                ym2.swal.timer(
                                    top.swal,
                                    data.msg,
                                    "自动跳转; <a href='<?= Url::to(App::params('admin.route.login'), '') ?>' target='_top'>立即跳转<a/>",
                                    function () {
                                        top.open("<?= Url::to(App::params('admin.route.login'), '') ?>", "_self");
                                    },
                                    3000
                                );

                                break;
                            default:
                                topToastr.error(data.msg);
                        }
                    }, function (error) {
                        ymSpinner.hide(flag);
                        topToastr.error(error.data || "系统错误, 发起请求失败!");
                        global.console.error(error);
                    });
                };
                $scope.actionDynamicSelectRefresh(null, true);

                // 动态下拉控件 - 新增
                $scope.actionDynamicSelectAdd = function (controlId) {
                    var openOption;
                    formDynamicSelect.forEach(function (value, index, array) {
                        if (controlId === value.__id) {
                            openOption = value.additionBtn;

                            switch (openOption.type) {
                                case "modal": //模态框
                                    // layer动态唯一索引
                                    var activeIndex = topLayer.index;
                                    // modal title
                                    var title = openOption.title || '';
                                    // modal width
                                    var width = openOption.width || "100%";
                                    // modal height
                                    var height = openOption.height || "100%";
                                    // modal footer close btn
                                    var footerCloseBtn = openOption.closeBtn;
                                    // layer screen obj
                                    var layerScreenObj = ym2.layerScreenOptions(width);
                                    var url = ym2.addUrlQueryParam(openOption.route, {
                                        __callId : value.__id,
                                    });

                                    // 挂载回调
                                    global.ym2CbkExport[value.__id] = function () {
                                        $scope.$apply(function () {
                                            $scope.actionDynamicSelectRefresh(value.__id);
                                        });
                                    };

                                    // iframe 模态框
                                    var layerCf = {
                                        type: 2, // iframe
                                        //skin: 'layui-layer-win10',
                                        area: [layerScreenObj.width, height],
                                        title: title,
                                        shade: 0.3, // 遮罩透明度
                                        shadeClose: false, // 点击遮罩区域，关闭弹层
                                        //closeBtn: layerScreenObj.closeBtn,
                                        maxmin: true, // 允许全屏最小化
                                        anim: 0, // 0-6 的动画形式，-1 不开启
                                        scrollbar: false, // 打开弹层时，是否允许浏览器出现滚动条。
                                        content: url,
                                        success: function(layero, index, that){
                                            // 弹层的最外层元素的 jQuery 对象
                                            //console.log(layero);
                                            // 弹层的索引值
                                            //console.log(index);
                                            // 弹层内部原型链中的 this --- 2.8+
                                            //console.log(that);
                                            // 获取iframe的窗口对象, 添加来源追踪
                                            var iframeWin = top[layero.find("iframe")[0]["name"]];
                                            iframeWin.__REFERER_WIN_NAME = global.name;
                                            //键盘事件关闭
                                            topJquery(".ym2_kc_" + activeIndex).focus().on("keydown", function (e) {
                                                // 空格和回车键
                                                if (e.keyCode === 13 || e.keyCode === 32) {
                                                    topJquery(this).trigger("click");
                                                }
                                            });
                                        },
                                    };
                                    if (footerCloseBtn) {
                                        layerCf.btn = ['<span class="ym2_keydown_close ym2_kc_' + activeIndex + '" tabindex="0">关闭</span>'];
                                    }

                                    topLayer.open(layerCf);

                                    break;
                                case "page": //单页
                                    var target = openOption.target;
                                    var owin;
                                    eval("owin = " + openOption.window);
                                    owin.open(openOption.route, target);

                                    break;
                            }
                        }
                    });
                };

                // 下拉联动监听
                $scope.callSelectLink = function (group, field, target, url, targetVal) {
                    var currentValue = $scope[group][field];
                    var targetGroup = target.group;
                    var targetField = target.field;
                    var queryParams = {};
                    var emptyValue = "\t\r\n";
                    targetVal = targetVal || emptyValue;

                    // 空值处理
                    if (!currentValue || !lodash.trim(currentValue)) {
                        // 初始化目标连接的值
                        $scope[targetGroup][targetField] = emptyValue;
                        // 初始化目标连接选项
                        $scope[targetGroup + '__' + targetField + '__options'] = [];
                        return;
                    }

                    queryParams[field] = currentValue;
                    // show loading
                    var flag = ymSpinner.show();
                    $http.get(ym2.addUrlQueryParam(url, queryParams)).then(function (result) {
                        ymSpinner.hide(flag);

                        var data = result.data;
                        switch (data.code) {
                            case <?= App::params('http.res.success') ?>:
                                // 设置目标连接选项
                                $scope[targetGroup + '__' + targetField + '__options'] = data.data || [];
                                Promise.resolve(true).then(function () {
                                    // 初始化目标连接的值
                                    $scope[targetGroup][targetField] = targetVal;
                                });

                                break;
                            case <?= App::params('http.res.failure') ?>:
                                topToastr.error(data.msg);

                                break;
                            case <?= App::params('http.res.unauthorized') ?>:
                                // 授权失效, 去登录
                                ym2.swal.timer(
                                    top.swal,
                                    data.msg,
                                    "自动跳转; <a href='<?= Url::to(App::params('admin.route.login'), '') ?>' target='_top'>立即跳转<a/>",
                                    function () {
                                        top.open("<?= Url::to(App::params('admin.route.login'), '') ?>", "_self");
                                    },
                                    3000
                                );

                                break;
                            default:
                                topToastr.error(data.msg);
                        }

                    }, function (error) {
                        ymSpinner.hide(flag);
                        topToastr.error(error.data || "系统错误, 发起请求失败!");
                        global.console.error(error);
                    });
                };

                // 表单数据模型监听
                <?php foreach ($formWatchScope as $index => $value): ?>

                var timer<?= $index ?>;
                $scope.$watch("<?= $value ?>", function (newVal, oldVal) {
                    // 表单触发器脚本
                    <?php foreach ($formTrigger as $item): ?>
                    <?php if (in_array($value, $item['watchScope'])): ?>

                    $scope.<?= $item['__scope'] ?> = <?= $item['where'] ?>;
                    <?php endif; ?>
                    <?php endforeach; ?>

                    // 表单值连接脚本
                    if (newVal !== oldVal) {
                        <?php foreach ($formValueLink as $item): ?>
                        <?php if (in_array($value, $item['watchScope'])): ?>

                        var params = {
                            <?php foreach ($item['sourceControl'] as $field => $vv): ?>

                            "<?= $field ?>": $scope.<?= $vv['__scope'] ?>,
                            <?php endforeach; ?>

                        };
                        if (timer<?= $index ?>) {
                            $timeout.cancel(timer<?= $index ?>);
                        }

                        timer<?= $index ?> = $timeout(function () {
                            $scope._actionVlinkRequest("<?= $item['targetRoute'] ?>", params, function (data) {
                                $scope.<?= $item['__targetScope'] ?> = data;
                            });
                        }, 250);
                        <?php endif; ?>
                        <?php endforeach; ?>

                    }

                }, true);
                <?php endforeach; ?>

                // 值连接HTTP请求
                $scope._actionVlinkRequest = function (url, params, successCallback) {
                    //发起请求
                    $http.post(url, params).then(function (result) {

                        var data = result.data;
                        switch (data.code) {
                            case <?= App::params('http.res.success') ?>:
                                successCallback(data.data);

                                break;
                            case <?= App::params('http.res.failure') ?>:
                                topToastr.error(data.msg || '结果无法识别');

                                break;
                            case <?= App::params('http.res.unauthorized') ?>:
                                // 授权失效, 去登录
                                ym2.swal.timer(
                                    top.swal,
                                    data.msg,
                                    "自动跳转; <a href='<?= Url::to(App::params('admin.route.login'), '') ?>' target='_top'>立即跳转<a/>",
                                    function () {
                                        top.open("<?= Url::to(App::params('admin.route.login'), '') ?>", "_self");
                                    },
                                    3000
                                );

                                break;
                            default:
                                topToastr.error(data.msg || '结果无法识别');
                        }

                    }, function (error) {
                        topToastr.error(error.data || "系统错误, 发起请求失败!");
                        global.console.error(error);
                    });
                };

                // 表单控件Range步进器事件(mousedown) +
                var TimerHandle = null;
                var TimeInterval = 130;
                $scope.triggerIncreaseStep = function ( group, field, step, max ) {
                    if ( TimerHandle !== null ) return;
                    var current = parseFloat( $scope[ group ][ field ] );
                    var callback = function () {
                        if ( current < max ) {
                            current += step;
                            if ( current >= max ) current = max;
                            $scope[ group ][ field ] = current;
                        }
                    };
                    callback();
                    TimerHandle = $interval( function () {
                        callback();
                    }, TimeInterval );
                };
                // 表单控件Range步进器事件(mousedown) -
                $scope.triggerDecreaseStep = function ( group, field, step, min ) {
                    if ( TimerHandle !== null ) return;
                    var current = parseFloat( $scope[ group ][ field ] );
                    var callback = function () {
                        if ( current > min ) {
                            current -= step;
                            if ( current <= min ) current = min;
                            $scope[ group ][ field ] = current;
                        }
                    };
                    callback();
                    TimerHandle = $interval( function () {
                        callback();
                    }, TimeInterval );
                };
                //表单控件Range步进器事件(mouseup) cancel timer
                $scope.cancelStepperTimer = function () {
                    if ( TimerHandle !== null ) {
                        $interval.cancel( TimerHandle );
                        TimerHandle = null;
                    }
                };
                //额外的JS脚本
                <?= !empty($extraJs) ? implode("\n", $extraJs) : '' ?>

                // 初始化表单
                $scope.formReset(null, true);

                // 导出表单数据,用于分步表单构建器
                global.ym2PageDataExport[formBuilderId] = $scope._actionFormValidation;

            }]);
    }(window, top);
</script>
